﻿//===============================================================================
//	PlayerLoginQueueManager.cpp
//	用户登录排队管理器
//===============================================================================

#include <list>
#include <ctime>

#include "ConstantDefine.h"

#include "PlayerLoginQueueManager.h"
#include "ManagerHelper.h"
#include "../../3rd/libjson/json.h"
#include "GameServer.h"
#include "../share/time_module.h"


PlayerLoginQueueManager::PlayerLoginQueueManager()
{
	m_lastTimeoutCheck = 0;
	m_max_login_accounts_num = 1;
	m_check_timeout_millsec = 60000;
}

PlayerLoginQueueManager::~PlayerLoginQueueManager()
{

}

void PlayerLoginQueueManager::Initialize(uint32_t maxNum, uint32_t millsec)
{
	if (maxNum > 0 && millsec > 0) {
		m_max_login_accounts_num = maxNum;
		m_check_timeout_millsec = millsec;
	}
}


void PlayerLoginQueueManager::checkLoginAccounts()
{
	uint64_t now = getNowMillsec();
	while (m_login_accounts.size() < m_max_login_accounts_num && m_wait_accounts.size() > 0)
	{
		LoginQueueInfo info = m_wait_accounts.front();
		m_wait_accounts.pop_front();

		if (check_connect(info.m_socketId))
		{
			info.m_status = LoginQueueInfo_Status_Login;
			info.m_time = now;
			m_login_accounts.push_back(info);
		}
	}
}

void PlayerLoginQueueManager::romveLoginAccount(uint32_t accountId)
{
	for (auto it = m_login_accounts.begin(); it != m_login_accounts.end(); ++it)
	{
		if (it->m_accountId == accountId)
		{
			m_login_accounts.erase(it);
			break;
		}
	}
}


uint32_t PlayerLoginQueueManager::checkWaitAccount(uint32_t accountId, uint32_t socketId, bool bInsert)
{
	// 检查超时
	checkTimeout();

	uint32_t status = LoginQueueInfo_Status_None;

	for (auto& info : m_wait_accounts)
	{
		if (info.m_accountId == accountId)
		{
			status = LoginQueueInfo_Status_Wait;
			info.m_socketId = socketId;
			break;
		}
	}

	if (status == LoginQueueInfo_Status_None)
	{
		for (auto info : m_login_accounts)
		{
			if (info.m_accountId == accountId)
			{
				info.m_socketId = socketId;
				if (info.m_status == LoginQueueInfo_Status_Login)
				{
					info.m_status = LoginQueueInfo_Status_LoginCheck;
				}
				status = info.m_status;
				break;
			}
		}
	}

	// 插入队列
	if (status == LoginQueueInfo_Status_None && bInsert)
	{
		status = LoginQueueInfo_Status_Wait;

		LoginQueueInfo info;
		info.m_accountId = accountId;
		info.m_socketId = socketId;
		info.m_status = status;
		info.m_time = getNowMillsec(); 

		if (m_login_accounts.size() < m_max_login_accounts_num)
		{
			// 直接标记为已检查
			status = LoginQueueInfo_Status_LoginCheck;
			info.m_status = status;
			m_login_accounts.push_back(info);

		}
		else
		{
			m_wait_accounts.push_back(info);
		}
	}

	return status;
}

LoginQueueWaitInfo PlayerLoginQueueManager::getLoginQueueInfo(uint32_t accountId, uint32_t socketId)
{
	checkTimeout();

	LoginQueueWaitInfo ret_info;
	ret_info.m_status = LoginQueueInfo_Status_None;
	ret_info.m_pos = 0;
	ret_info.m_wait = 0;

	bool bFind = false;
	int32_t pos = 0;
	for (auto& info : m_wait_accounts)
	{
		pos++;
		if (info.m_accountId == accountId || info.m_socketId == socketId)
		{
			ret_info.m_status = info.m_status;
			ret_info.m_pos = pos;
			ret_info.m_wait = pos * m_check_timeout_millsec / m_max_login_accounts_num;
			bFind = true;
			break;
		}
	}

	if (!bFind) {
		for (auto info : m_login_accounts)
		{
			if (info.m_accountId == accountId || info.m_socketId == socketId)
			{
				ret_info.m_status = info.m_status;
				bFind = true;
				break;
			}
		}
	}

	return ret_info;
}


void PlayerLoginQueueManager::checkTimeout()
{
	uint64_t now = getNowMillsec();

	if (m_lastTimeoutCheck + m_check_timeout_millsec < now)
	{
		// 时间没到
		return;
	}
	m_lastTimeoutCheck = now;

	// 超时检测
	std::list<uint32_t> timeoutAccounts;
	for (auto info : m_login_accounts)
	{
		if (info.m_time + m_check_timeout_millsec > now)
		{
			// 超时
			timeoutAccounts.push_back(info.m_accountId);
		}
	}

	// 删除
	for (auto rId : timeoutAccounts)
	{
		romveLoginAccount(rId);
	}

	checkLoginAccounts();
}

void PlayerLoginQueueManager::disconnect(uint32_t socketId)
{
	for (auto it = m_login_accounts.begin(); it != m_login_accounts.end(); ++it)
	{
		if (it->m_socketId == socketId)
		{
			// 断线删除
			m_login_accounts.erase(it);
			break;
		}
	}

	checkLoginAccounts();
}

bool PlayerLoginQueueManager::check_connect(uint32_t socketId)
{
	return GameServer::GetInstance().is_connnected(socketId);
}

void PlayerLoginQueueManager::accountloginBegin(uint32_t accountId)
{
	for (auto info : m_login_accounts)
	{
		if (info.m_accountId == accountId)
		{
			info.m_status = LoginQueueInfo_Status_LoginBegin;
			break;
		}
	}
}

void PlayerLoginQueueManager::accountloginFinished(uint32_t accountId)
{
	romveLoginAccount(accountId);
}

uint64_t PlayerLoginQueueManager::getNowMillsec()
{
	uint64_t now = CUR_MS;
	return now;
}